package net.cxd.cahce.core;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.cxd.cahce.ann.Id;
import net.cxd.cahce.ann.Key;

public class Connection {
	private Map<Object, Object> map;
	private Map<Object, Object> keyMap;
	private String name;
	private Class clazz;

	public String getName() {
		return name;
	}

	private Connection() {
	}

	Connection(Map<Object, Object> map, Class clazz, Map<Object, Object> keyMap) {
		this.map = map;
		this.clazz = clazz;
		this.name = clazz.getSimpleName();
		this.keyMap = keyMap;
	}

	public void save(Object o) {
		try {
			Field[] fs = o.getClass().getDeclaredFields();
			Object key1 = null;
			for (int i = 0; i < fs.length; i++) {
				if (fs[i].getAnnotation(Id.class) != null) {
					fs[i].setAccessible(true);
					key1 = fs[i].get(o);
					map.put(key1, o);// key --> value
				} else if (fs[i].getAnnotation(Key.class) != null) {
					// TODO save the other key
					fs[i].setAccessible(true);
					List<Object> list = (List<Object>) keyMap.get(fs[i].get(o));
					if (list == null) {
						list = new ArrayList<Object>();
					}

					if (key1 != null) {
						list.add(key1);
					} else {
						for (int j = 0; i < fs.length; j++) {
							if (fs[j].getAnnotation(Id.class) != null) {
								fs[j].setAccessible(true);
								key1 = fs[j].get(o);
								list.add(key1);
								// map.put(key1, o);// key --> value
							}
						}
					}
					keyMap.put(fs[i].get(o), list);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void remove(Object o) {
		try {
			Field[] fs = o.getClass().getDeclaredFields();
			Object key1 = null;
			for (int i = 0; i < fs.length; i++) {
				if (fs[i].getAnnotation(Id.class) != null) {
					fs[i].setAccessible(true);
					key1 = fs[i].get(o);
					if (map.containsKey(key1)) {
						o = map.get(key1);
						map.remove(o);
						break;
					} else {
						return;
					}
				}
			}
			if (keyMap == null || keyMap.size() == 0) {
				return;
			}
			for (int i = 0; i < fs.length; i++) {
				if (fs[i].getAnnotation(Key.class) != null) {
					fs[i].setAccessible(true);
					Object key3 = fs[i].get(o);
					List<Object> list = (List<Object>) keyMap.get(key3);
					if (list == null) {
						continue;
					} else {
						for (Object obj : list) {
							if (obj == key1) {
								list.remove(obj);
								keyMap.put(key3, list);
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void remove(Serializable id) {
		Object o = map.get(id);
		if (o != null) {
			remove(o);
		}
	}

	public void removeAll() {
		map.clear();
		keyMap.clear();
	}

	public Object find(Object o) {
		try {
			Field[] fs = o.getClass().getDeclaredFields();
			Object key1 = null;
			for (int i = 0; i < fs.length; i++) {
				if (fs[i].getAnnotation(Id.class) != null) {
					fs[i].setAccessible(true);
					key1 = fs[i].get(o);
					return map.get(key1);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public Object findById(Object id) {
		return map.get(id);
	}

	//
	public List<Object> findByKeys(Map<String, Object> map1) {
		try {

			Set<String> keySet = map1.keySet();
			Iterator<String> it = keySet.iterator();
			boolean flag = true;
			List<Object> list = null;
			List<String> keys = new ArrayList<String>();
			while (it.hasNext()) {
				keys.add(it.next());
			}
			if (keys.size() > 0) {
				list = (List<Object>) keyMap.get(map1.get(keys.get(0)));
				if (list != null && list.size() > 0) {
					List<Object> ret = new ArrayList<Object>();
					loop: 
					for (Object obj : list) {
						Object entity = findById(obj);
						for (String key : keys) {
							Object value = map1.get(key);
							Field f = clazz.getDeclaredField(key);
							f.setAccessible(true);
							Object oo = f.get(entity);
							Object v = map1.get(key);
							if (oo != v && ! oo.equals(v)) {
								break loop;
							}
						}
						ret.add(entity);
					}
					return ret;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public void update(Object o){//删除以前key对应的id    更新现在的数据
		try {
			Field[] fs = o.getClass().getDeclaredFields();
			Object key1 = null;
			for (Field f : fs) {
				if (f.getAnnotation(Id.class) != null) {// 获取key
					f.setAccessible(true);
					key1 = f.get(o);
					break;
				}
			}
			remove(key1);
			save(o);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	


}
